#include "syntree.h"

// syntree_node : alloue un noeud de l'arbre
syntree* syntree_node(void)
{
	return malloc(sizeof(syntree));
}

//Toutes les fonctions qui suivent fonctionnent de la même manière,
//elles allouent la place pour un noeud et renseigne les informations
//récupérées dans les actions de la grammaire

// _id : créé un noeud pour les identifiants lors de leur déclaration
syntree* _id(char* id)
{
	syntree* n  = syntree_node();
	n->type     = T_ID;
	
	symtable* sym = table_get_str(table, id);
	if (sym == NULL)
	{
		yyerror((char*) g_strdup_printf((const gchar*)
		        "L'identifiant '%s' n'a pas encore été déclaré.", id));
		return NULL;
	}
	
	n->id.index = sym->index;
	n->id.id    = malloc((strlen(id)+1) * sizeof(char));
	n->id.id    = strcpy(n->id.id, id);
	
	return n;
}

// _id : créé un noeud pour les identifiants lorsqu'on les rencontre dans le code
syntree* _id_str(char* str)
{
	syntree* n    = syntree_node();
	n->type       = T_ID_STR;
	n->id_str.str = malloc((strlen(str)+1) * sizeof(char));
	n->id_str.str = strcpy(n->id_str.str, str);
	
	return n;
}

// _id : créé un noeud pour les types atomiques
syntree* _type(int type)
{
	syntree* n    = syntree_node();
	n->type       = T_TYPE;
	n->_type.type = type;
	
	return n;
}

// _str : créé un noeud pour les chaînes de caractères
syntree* _str(char* str)
{
	syntree* n    = syntree_node();
	n->type       = T_STRING;
	n->string.str = malloc((strlen(str)+1) * sizeof(char));
	n->string.str = strcpy(n->string.str, str);
	n->string.label = (char*) g_strdup_printf((const gchar*) "str_%d", labelno++);
	
	return n;
}

// _int : créé un noeud pour les entiers
syntree* _int(int value)
{
	syntree* n       = syntree_node();
	n->type          = T_INT;
	n->integer.value = value;
	return n;
}

// _bool : créé un noeud pour les booléens
syntree* _bool(int value)
{
	syntree* n       = syntree_node();
	n->type          = T_BOOL;
	n->boolean.value = value;
	
	return n;
}

// _range : créé un noeud pour les range
syntree* _range(int debut, int fin)
{
	syntree* n     = syntree_node();
	n->type        = T_RANGE;
	n->range.debut = debut;
	n->range.fin   = fin;
	
	return n;
}

// _range : créé un noeud pour les tableaux
syntree* _type_array(syntree* rangelist, int type)
{
	syntree* n        = syntree_node();
	n->type           = T_ARRAY;
	n->array.type     = type;
	n->array.debutTab = rangelist->range.debut;
	n->array.finTab   = rangelist->range.fin;
	n->array.nbDim    = 1;
	
	return n;
}

// _op : créé un noeud pour les opérations
syntree* _op(int opr, int nop, ...)
{
	va_list ap;
	int i;
	
	syntree* n = syntree_node();
	n->type    = T_OP;
	
	n->op.opr = opr;
	n->op.nop = nop;
	
	// Allocation des noeuds des opérandes
	n->op.op = malloc((nop+1) * sizeof(syntree));
	n->op.op[nop] = NULL;
	
	// Gestion des arguments
	va_start(ap, nop);
	for (i = 0; i < nop; i++)
	{
		n->op.op[i] = va_arg(ap, syntree*);
	}
	va_end(ap);
	
	return n;
}

// syntree_free : libère la mémoire allouée pour l'arbre via parcours
void syntree_free(syntree* tree)
{
	int i;
	
	if (tree == NULL) return;
	
	switch(tree->type)
	{
		case T_STRING :
			free(tree->string.str);
			break;
		case T_OP :
			for (i = 0; i < tree->op.nop; i++)
			{
				syntree_free(tree->op.op[i]);
			}
			break;
		default :
			/* Rien */
			break;
	}
	
	free(tree);
}


